/*
Copyright (c) 2008, Yahoo! Inc. All rights reserved.
Code licensed under the BSD License:
http://developer.yahoo.net/yui/license.txt
version: 2.6.0
*/
/**
 * The YAHOO object is the single global object used by YUI Library.  It
 * contains utility function for setting up namespaces, inheritance, and
 * logging.  YAHOO.util, YAHOO.widget, and YAHOO.example are namespaces
 * created automatically for and used by the library.
 * @module yahoo
 * @title  YAHOO Global
 */

/**
 * YAHOO_config is not included as part of the library.  Instead it is an 
 * object that can be defined by the implementer immediately before 
 * including the YUI library.  The properties included in this object
 * will be used to configure global properties needed as soon as the 
 * library begins to load.
 * @class YAHOO_config
 * @static
 */

/**
 * A reference to a function that will be executed every time a YAHOO module
 * is loaded.  As parameter, this function will receive the version
 * information for the module. See <a href="YAHOO.env.html#getVersion">
 * YAHOO.env.getVersion</a> for the description of the version data structure.
 * @property listener
 * @type Function
 * @static
 * @default undefined
 */

/**
 * Set to true if the library will be dynamically loaded after window.onload.
 * Defaults to false 
 * @property injecting
 * @type boolean
 * @static
 * @default undefined
 */

/**
 * Instructs the yuiloader component to dynamically load yui components and
 * their dependencies.  See the yuiloader documentation for more information
 * about dynamic loading
 * @property load
 * @static
 * @default undefined
 * @see yuiloader
 */

/**
 * Forces the use of the supplied locale where applicable in the library
 * @property locale
 * @type string
 * @static
 * @default undefined
 */

if (typeof YAHOO == "undefined" || !YAHOO) {
    /**
     * The YAHOO global namespace object.  If YAHOO is already defined, the
     * existing YAHOO object will not be overwritten so that defined
     * namespaces are preserved.
     * @class YAHOO
     * @static
     */
    var YAHOO = {};
}

/**
 * Returns the namespace specified and creates it if it doesn't exist
 * <pre>
 * YAHOO.namespace("property.package");
 * YAHOO.namespace("YAHOO.property.package");
 * </pre>
 * Either of the above would create YAHOO.property, then
 * YAHOO.property.package
 *
 * Be careful when naming packages. Reserved words may work in some browsers
 * and not others. For instance, the following will fail in Safari:
 * <pre>
 * YAHOO.namespace("really.long.nested.namespace");
 * </pre>
 * This fails because "long" is a future reserved word in ECMAScript
 *
 * @method namespace
 * @static
 * @param  {String*} arguments 1-n namespaces to create 
 * @return {Object}  A reference to the last namespace object created
 */
YAHOO.namespace = function() {
    var a=arguments, o=null, i, j, d;
    for (i=0; i<a.length; i=i+1) {
        d=a[i].split(".");
        o=YAHOO;

        // YAHOO is implied, so it is ignored if it is included
        for (j=(d[0] == "YAHOO") ? 1 : 0; j<d.length; j=j+1) {
            o[d[j]]=o[d[j]] || {};
            o=o[d[j]];
        }
    }

    return o;
};

/**
 * Uses YAHOO.widget.Logger to output a log message, if the widget is
 * available.
 *
 * @method log
 * @static
 * @param  {String}  msg  The message to log.
 * @param  {String}  cat  The log category for the message.  Default
 *                        categories are "info", "warn", "error", time".
 *                        Custom categories can be used as well. (opt)
 * @param  {String}  src  The source of the the message (opt)
 * @return {Boolean}      True if the log operation was successful.
 */
YAHOO.log = function(msg, cat, src) {
    var l=YAHOO.widget.Logger;
    if(l && l.log) {
        return l.log(msg, cat, src);
    } else {
        return false;
    }
};

/**
 * Registers a module with the YAHOO object
 * @method register
 * @static
 * @param {String}   name    the name of the module (event, slider, etc)
 * @param {Function} mainClass a reference to class in the module.  This
 *                             class will be tagged with the version info
 *                             so that it will be possible to identify the
 *                             version that is in use when multiple versions
 *                             have loaded
 * @param {Object}   data      metadata object for the module.  Currently it
 *                             is expected to contain a "version" property
 *                             and a "build" property at minimum.
 */
YAHOO.register = function(name, mainClass, data) {
    var mods = YAHOO.env.modules;
    if (!mods[name]) {
        mods[name] = { versions:[], builds:[] };
    }
    var m=mods[name],v=data.version,b=data.build,ls=YAHOO.env.listeners;
    m.name = name;
    m.version = v;
    m.build = b;
    m.versions.push(v);
    m.builds.push(b);
    m.mainClass = mainClass;
    // fire the module load listeners
    for (var i=0;i<ls.length;i=i+1) {
        ls[i](m);
    }
    // label the main class
    if (mainClass) {
        mainClass.VERSION = v;
        mainClass.BUILD = b;
    } else {
        YAHOO.log("mainClass is undefined for module " + name, "warn");
    }
};

/**
 * YAHOO.env is used to keep track of what is known about the YUI library and
 * the browsing environment
 * @class YAHOO.env
 * @static
 */
YAHOO.env = YAHOO.env || {

    /**
     * Keeps the version info for all YUI modules that have reported themselves
     * @property modules
     * @type Object[]
     */
    modules: [],
    
    /**
     * List of functions that should be executed every time a YUI module
     * reports itself.
     * @property listeners
     * @type Function[]
     */
    listeners: []
};

/**
 * Returns the version data for the specified module:
 *      <dl>
 *      <dt>name:</dt>      <dd>The name of the module</dd>
 *      <dt>version:</dt>   <dd>The version in use</dd>
 *      <dt>build:</dt>     <dd>The build number in use</dd>
 *      <dt>versions:</dt>  <dd>All versions that were registered</dd>
 *      <dt>builds:</dt>    <dd>All builds that were registered.</dd>
 *      <dt>mainClass:</dt> <dd>An object that was was stamped with the
 *                 current version and build. If 
 *                 mainClass.VERSION != version or mainClass.BUILD != build,
 *                 multiple versions of pieces of the library have been
 *                 loaded, potentially causing issues.</dd>
 *       </dl>
 *
 * @method getVersion
 * @static
 * @param {String}  name the name of the module (event, slider, etc)
 * @return {Object} The version info
 */
YAHOO.env.getVersion = function(name) {
    return YAHOO.env.modules[name] || null;
};

/**
 * Do not fork for a browser if it can be avoided.  Use feature detection when
 * you can.  Use the user agent as a last resort.  YAHOO.env.ua stores a version
 * number for the browser engine, 0 otherwise.  This value may or may not map
 * to the version number of the browser using the engine.  The value is 
 * presented as a float so that it can easily be used for boolean evaluation 
 * as well as for looking for a particular range of versions.  Because of this, 
 * some of the granularity of the version info may be lost (e.g., Gecko 1.8.0.9 
 * reports 1.8).
 * @class YAHOO.env.ua
 * @static
 */
YAHOO.env.ua = function() {
    var o={

        /**
         * Internet Explorer version number or 0.  Example: 6
         * @property ie
         * @type float
         */
        ie:0,

        /**
         * Opera version number or 0.  Example: 9.2
         * @property opera
         * @type float
         */
        opera:0,

        /**
         * Gecko engine revision number.  Will evaluate to 1 if Gecko 
         * is detected but the revision could not be found. Other browsers
         * will be 0.  Example: 1.8
         * <pre>
         * Firefox 1.0.0.4: 1.7.8   <-- Reports 1.7
         * Firefox 1.5.0.9: 1.8.0.9 <-- Reports 1.8
         * Firefox 2.0.0.3: 1.8.1.3 <-- Reports 1.8
         * Firefox 3 alpha: 1.9a4   <-- Reports 1.9
         * </pre>
         * @property gecko
         * @type float
         */
        gecko:0,

        /**
         * AppleWebKit version.  KHTML browsers that are not WebKit browsers 
         * will evaluate to 1, other browsers 0.  Example: 418.9.1
         * <pre>
         * Safari 1.3.2 (312.6): 312.8.1 <-- Reports 312.8 -- currently the 
         *                                   latest available for Mac OSX 10.3.
         * Safari 2.0.2:         416     <-- hasOwnProperty introduced
         * Safari 2.0.4:         418     <-- preventDefault fixed
         * Safari 2.0.4 (419.3): 418.9.1 <-- One version of Safari may run
         *                                   different versions of webkit
         * Safari 2.0.4 (419.3): 419     <-- Tiger installations that have been
         *                                   updated, but not updated
         *                                   to the latest patch.
         * Webkit 212 nightly:   522+    <-- Safari 3.0 precursor (with native SVG
         *                                   and many major issues fixed).  
         * 3.x yahoo.com, flickr:422     <-- Safari 3.x hacks the user agent
         *                                   string when hitting yahoo.com and 
         *                                   flickr.com.
         * Safari 3.0.4 (523.12):523.12  <-- First Tiger release - automatic update
         *                                   from 2.x via the 10.4.11 OS patch
         * Webkit nightly 1/2008:525+    <-- Supports DOMContentLoaded event.
         *                                   yahoo.com user agent hack removed.
         *                                   
         * </pre>
         * http://developer.apple.com/internet/safari/uamatrix.html
         * @property webkit
         * @type float
         */
        webkit: 0,

        /**
         * The mobile property will be set to a string containing any relevant
         * user agent information when a modern mobile browser is detected.
         * Currently limited to Safari on the iPhone/iPod Touch, Nokia N-series
         * devices with the WebKit-based browser, and Opera Mini.  
         * @property mobile 
         * @type string
         */
        mobile: null,

        /**
         * Adobe AIR version number or 0.  Only populated if webkit is detected.
         * Example: 1.0
         * @property air
         * @type float
         */
        air: 0

    };

    var ua=navigator.userAgent, m;

    // Modern KHTML browsers should qualify as Safari X-Grade
    if ((/KHTML/).test(ua)) {
        o.webkit=1;
    }
    // Modern WebKit browsers are at least X-Grade
    m=ua.match(/AppleWebKit\/([^\s]*)/);
    if (m&&m[1]) {
        o.webkit=parseFloat(m[1]);

        // Mobile browser check
        if (/ Mobile\//.test(ua)) {
            o.mobile = "Apple"; // iPhone or iPod Touch
        } else {
            m=ua.match(/NokiaN[^\/]*/);
            if (m) {
                o.mobile = m[0]; // Nokia N-series, ex: NokiaN95
            }
        }

        m=ua.match(/AdobeAIR\/([^\s]*)/);
        if (m) {
            o.air = m[0]; // Adobe AIR 1.0 or better
        }

    }

    if (!o.webkit) { // not webkit
        // @todo check Opera/8.01 (J2ME/MIDP; Opera Mini/2.0.4509/1316; fi; U; ssr)
        m=ua.match(/Opera[\s\/]([^\s]*)/);
        if (m&&m[1]) {
            o.opera=parseFloat(m[1]);
            m=ua.match(/Opera Mini[^;]*/);
            if (m) {
                o.mobile = m[0]; // ex: Opera Mini/2.0.4509/1316
            }
        } else { // not opera or webkit
            m=ua.match(/MSIE\s([^;]*)/);
            if (m&&m[1]) {
                o.ie=parseFloat(m[1]);
            } else { // not opera, webkit, or ie
                m=ua.match(/Gecko\/([^\s]*)/);
                if (m) {
                    o.gecko=1; // Gecko detected, look for revision
                    m=ua.match(/rv:([^\s\)]*)/);
                    if (m&&m[1]) {
                        o.gecko=parseFloat(m[1]);
                    }
                }
            }
        }
    }
    
    return o;
}();

/*
 * Initializes the global by creating the default namespaces and applying
 * any new configuration information that is detected.  This is the setup
 * for env.
 * @method init
 * @static
 * @private
 */
(function() {
    YAHOO.namespace("util", "widget", "example");
    if ("undefined" !== typeof YAHOO_config) {
        var l=YAHOO_config.listener,ls=YAHOO.env.listeners,unique=true,i;
        if (l) {
            // if YAHOO is loaded multiple times we need to check to see if
            // this is a new config object.  If it is, add the new component
            // load listener to the stack
            for (i=0;i<ls.length;i=i+1) {
                if (ls[i]==l) {
                    unique=false;
                    break;
                }
            }
            if (unique) {
                ls.push(l);
            }
        }
    }
})();
/**
 * Provides the language utilites and extensions used by the library
 * @class YAHOO.lang
 */
YAHOO.lang = YAHOO.lang || {};

(function() {

    var L = YAHOO.lang,

    // ADD = ["toString", "valueOf", "hasOwnProperty"],
    ADD = ["toString", "valueOf"],

    OB = {

        /**
        * Determines whether or not the provided object is an array.
        * Testing typeof/instanceof/constructor of arrays across frame 
        * boundaries isn't possible in Safari unless you have a reference
        * to the other frame to test against its Array prototype.  To
        * handle this case, we test well-known array properties instead.
        * properties.
        * @method isArray
        * @param {any} o The object being testing
        * @return {boolean} the result
        */
        isArray: function(o) {
        if (o) {
                return L.isNumber(o.length) && L.isFunction(o.splice);
            }
            return false;
        },

        /**
        * Determines whether or not the provided object is a boolean
        * @method isBoolean
        * @param {any} o The object being testing
        * @return {boolean} the result
        */
        isBoolean: function(o) {
            return typeof o === 'boolean';
        },

        /**
        * Determines whether or not the provided object is a function
        * @method isFunction
        * @param {any} o The object being testing
        * @return {boolean} the result
        */
        isFunction: function(o) {
            return typeof o === 'function';
        },

        /**
        * Determines whether or not the provided object is null
        * @method isNull
        * @param {any} o The object being testing
        * @return {boolean} the result
        */
        isNull: function(o) {
            return o === null;
        },

        /**
        * Determines whether or not the provided object is a legal number
        * @method isNumber
        * @param {any} o The object being testing
        * @return {boolean} the result
        */
        isNumber: function(o) {
            return typeof o === 'number' && isFinite(o);
        },

        /**
        * Determines whether or not the provided object is of type object
        * or function
        * @method isObject
        * @param {any} o The object being testing
        * @return {boolean} the result
        */
        isObject: function(o) {
            return (o && (typeof o === 'object' || L.isFunction(o))) || false;
        },

        /**
        * Determines whether or not the provided object is a string
        * @method isString
        * @param {any} o The object being testing
        * @return {boolean} the result
        */
        isString: function(o) {
            return typeof o === 'string';
        },

        /**
        * Determines whether or not the provided object is undefined
        * @method isUndefined
        * @param {any} o The object being testing
        * @return {boolean} the result
        */
        isUndefined: function(o) {
            return typeof o === 'undefined';
        },


        /**
        * IE will not enumerate native functions in a derived object even if the
        * function was overridden.  This is a workaround for specific functions 
        * we care about on the Object prototype. 
        * @property _IEEnumFix
        * @param {Function} r  the object to receive the augmentation
        * @param {Function} s  the object that supplies the properties to augment
        * @static
        * @private
        */
        _IEEnumFix: (YAHOO.env.ua.ie) ? function(r, s) {
            for (var i = 0; i < ADD.length; i = i + 1) {
                var fname = ADD[i], f = s[fname];
                if (L.isFunction(f) && f != Object.prototype[fname]) {
                    r[fname] = f;
                }
            }
        } : function() { },

        /**
        * Utility to set up the prototype, constructor and superclass properties to
        * support an inheritance strategy that can chain constructors and methods.
        * Static members will not be inherited.
        *
        * @method extend
        * @static
        * @param {Function} subc   the object to modify
        * @param {Function} superc the object to inherit
        * @param {Object} overrides  additional properties/methods to add to the
        *                              subclass prototype.  These will override the
        *                              matching items obtained from the superclass 
        *                              if present.
        */
        extend: function(subc, superc, overrides) {
            if (!superc || !subc) {
                throw new Error("extend failed, please check that " +
                            "all dependencies are included.");
            }
            var F = function() { };
            F.prototype = superc.prototype;
            subc.prototype = new F();
            subc.prototype.constructor = subc;
            subc.superclass = superc.prototype;
            if (superc.prototype.constructor == Object.prototype.constructor) {
                superc.prototype.constructor = superc;
            }

            if (overrides) {
                for (var i in overrides) {
                    if (L.hasOwnProperty(overrides, i)) {
                        subc.prototype[i] = overrides[i];
                    }
                }

                L._IEEnumFix(subc.prototype, overrides);
            }
        },

        /**
        * Applies all properties in the supplier to the receiver if the
        * receiver does not have these properties yet.  Optionally, one or 
        * more methods/properties can be specified (as additional 
        * parameters).  This option will overwrite the property if receiver 
        * has it already.  If true is passed as the third parameter, all 
        * properties will be applied and _will_ overwrite properties in 
        * the receiver.
        *
        * @method augmentObject
        * @static
        * @since 2.3.0
        * @param {Function} r  the object to receive the augmentation
        * @param {Function} s  the object that supplies the properties to augment
        * @param {String*|boolean}  arguments zero or more properties methods 
        *        to augment the receiver with.  If none specified, everything
        *        in the supplier will be used unless it would
        *        overwrite an existing property in the receiver. If true
        *        is specified as the third parameter, all properties will
        *        be applied and will overwrite an existing property in
        *        the receiver
        */
        augmentObject: function(r, s) {
            if (!s || !r) {
                throw new Error("Absorb failed, verify dependencies.");
            }
            var a = arguments, i, p, override = a[2];
            if (override && override !== true) { // only absorb the specified properties
                for (i = 2; i < a.length; i = i + 1) {
                    r[a[i]] = s[a[i]];
                }
            } else { // take everything, overwriting only if the third parameter is true
                for (p in s) {
                    if (override || !(p in r)) {
                        r[p] = s[p];
                    }
                }

                L._IEEnumFix(r, s);
            }
        },

        /**
        * Same as YAHOO.lang.augmentObject, except it only applies prototype properties
        * @see YAHOO.lang.augmentObject
        * @method augmentProto
        * @static
        * @param {Function} r  the object to receive the augmentation
        * @param {Function} s  the object that supplies the properties to augment
        * @param {String*|boolean}  arguments zero or more properties methods 
        *        to augment the receiver with.  If none specified, everything 
        *        in the supplier will be used unless it would overwrite an existing 
        *        property in the receiver.  if true is specified as the third 
        *        parameter, all properties will be applied and will overwrite an 
        *        existing property in the receiver
        */
        augmentProto: function(r, s) {
            if (!s || !r) {
                throw new Error("Augment failed, verify dependencies.");
            }
            //var a=[].concat(arguments);
            var a = [r.prototype, s.prototype];
            for (var i = 2; i < arguments.length; i = i + 1) {
                a.push(arguments[i]);
            }
            L.augmentObject.apply(this, a);
        },


        /**
        * Returns a simple string representation of the object or array.
        * Other types of objects will be returned unprocessed.  Arrays
        * are expected to be indexed.  Use object notation for
        * associative arrays.
        * @method dump
        * @since 2.3.0
        * @param o {Object} The object to dump
        * @param d {int} How deep to recurse child objects, default 3
        * @return {String} the dump result
        */
        dump: function(o, d) {
            var i, len, s = [], OBJ = "{...}", FUN = "f(){...}",
            COMMA = ', ', ARROW = ' => ';

            // Cast non-objects to string
            // Skip dates because the std toString is what we want
            // Skip HTMLElement-like objects because trying to dump 
            // an element will cause an unhandled exception in FF 2.x
            if (!L.isObject(o)) {
                return o + "";
            } else if (o instanceof Date || ("nodeType" in o && "tagName" in o)) {
                return o;
            } else if (L.isFunction(o)) {
                return FUN;
            }

            // dig into child objects the depth specifed. Default 3
            d = (L.isNumber(d)) ? d : 3;

            // arrays [1, 2, 3]
            if (L.isArray(o)) {
                s.push("[");
                for (i = 0, len = o.length; i < len; i = i + 1) {
                    if (L.isObject(o[i])) {
                        s.push((d > 0) ? L.dump(o[i], d - 1) : OBJ);
                    } else {
                        s.push(o[i]);
                    }
                    s.push(COMMA);
                }
                if (s.length > 1) {
                    s.pop();
                }
                s.push("]");
                // objects {k1 => v1, k2 => v2}
            } else {
                s.push("{");
                for (i in o) {
                    if (L.hasOwnProperty(o, i)) {
                        s.push(i + ARROW);
                        if (L.isObject(o[i])) {
                            s.push((d > 0) ? L.dump(o[i], d - 1) : OBJ);
                        } else {
                            s.push(o[i]);
                        }
                        s.push(COMMA);
                    }
                }
                if (s.length > 1) {
                    s.pop();
                }
                s.push("}");
            }

            return s.join("");
        },

        /**
        * Does variable substitution on a string. It scans through the string 
        * looking for expressions enclosed in { } braces. If an expression 
        * is found, it is used a key on the object.  If there is a space in
        * the key, the first word is used for the key and the rest is provided
        * to an optional function to be used to programatically determine the
        * value (the extra information might be used for this decision). If 
        * the value for the key in the object, or what is returned from the
        * function has a string value, number value, or object value, it is 
        * substituted for the bracket expression and it repeats.  If this
        * value is an object, it uses the Object's toString() if this has
        * been overridden, otherwise it does a shallow dump of the key/value
        * pairs.
        * @method substitute
        * @since 2.3.0
        * @param s {String} The string that will be modified.
        * @param o {Object} An object containing the replacement values
        * @param f {Function} An optional function that can be used to
        *                     process each match.  It receives the key,
        *                     value, and any extra metadata included with
        *                     the key inside of the braces.
        * @return {String} the substituted string
        */
        substitute: function(s, o, f) {
            var i, j, k, key, v, meta, saved = [], token,
            DUMP = 'dump', SPACE = ' ', LBRACE = '{', RBRACE = '}';


            for (; ; ) {
                i = s.lastIndexOf(LBRACE);
                if (i < 0) {
                    break;
                }
                j = s.indexOf(RBRACE, i);
                if (i + 1 >= j) {
                    break;
                }

                //Extract key and meta info 
                token = s.substring(i + 1, j);
                key = token;
                meta = null;
                k = key.indexOf(SPACE);
                if (k > -1) {
                    meta = key.substring(k + 1);
                    key = key.substring(0, k);
                }

                // lookup the value
                v = o[key];

                // if a substitution function was provided, execute it
                if (f) {
                    v = f(key, v, meta);
                }

                if (L.isObject(v)) {
                    if (L.isArray(v)) {
                        v = L.dump(v, parseInt(meta, 10));
                    } else {
                        meta = meta || "";

                        // look for the keyword 'dump', if found force obj dump
                        var dump = meta.indexOf(DUMP);
                        if (dump > -1) {
                            meta = meta.substring(4);
                        }

                        // use the toString if it is not the Object toString 
                        // and the 'dump' meta info was not found
                        if (v.toString === Object.prototype.toString || dump > -1) {
                            v = L.dump(v, parseInt(meta, 10));
                        } else {
                            v = v.toString();
                        }
                    }
                } else if (!L.isString(v) && !L.isNumber(v)) {
                    // This {block} has no replace string. Save it for later.
                    v = "~-" + saved.length + "-~";
                    saved[saved.length] = token;

                    // break;
                }

                s = s.substring(0, i) + v + s.substring(j + 1);


            }

            // restore saved {block}s
            for (i = saved.length - 1; i >= 0; i = i - 1) {
                s = s.replace(new RegExp("~-" + i + "-~"), "{" + saved[i] + "}", "g");
            }

            return s;
        },


        /**
        * Returns a string without any leading or trailing whitespace.  If 
        * the input is not a string, the input will be returned untouched.
        * @method trim
        * @since 2.3.0
        * @param s {string} the string to trim
        * @return {string} the trimmed string
        */
        trim: function(s) {
            try {
                return s.replace(/^\s+|\s+$/g, "");
            } catch (e) {
                return s;
            }
        },

        /**
        * Returns a new object containing all of the properties of
        * all the supplied objects.  The properties from later objects
        * will overwrite those in earlier objects.
        * @method merge
        * @since 2.3.0
        * @param arguments {Object*} the objects to merge
        * @return the new merged object
        */
        merge: function() {
            var o = {}, a = arguments;
            for (var i = 0, l = a.length; i < l; i = i + 1) {
                L.augmentObject(o, a[i], true);
            }
            return o;
        },

        /**
        * Executes the supplied function in the context of the supplied 
        * object 'when' milliseconds later.  Executes the function a 
        * single time unless periodic is set to true.
        * @method later
        * @since 2.4.0
        * @param when {int} the number of milliseconds to wait until the fn 
        * is executed
        * @param o the context object
        * @param fn {Function|String} the function to execute or the name of 
        * the method in the 'o' object to execute
        * @param data [Array] data that is provided to the function.  This accepts
        * either a single item or an array.  If an array is provided, the
        * function is executed with one parameter for each array item.  If
        * you need to pass a single array parameter, it needs to be wrapped in
        * an array [myarray]
        * @param periodic {boolean} if true, executes continuously at supplied 
        * interval until canceled
        * @return a timer object. Call the cancel() method on this object to 
        * stop the timer.
        */
        later: function(when, o, fn, data, periodic) {
            when = when || 0;
            o = o || {};
            var m = fn, d = data, f, r;

            if (L.isString(fn)) {
                m = o[fn];
            }

            if (!m) {
                throw new TypeError("method undefined");
            }

            if (!L.isArray(d)) {
                d = [data];
            }

            f = function() {
                m.apply(o, d);
            };

            r = (periodic) ? setInterval(f, when) : setTimeout(f, when);

            return {
                interval: periodic,
                cancel: function() {
                    if (this.interval) {
                        clearInterval(r);
                    } else {
                        clearTimeout(r);
                    }
                }
            };
        },

        /**
        * A convenience method for detecting a legitimate non-null value.
        * Returns false for null/undefined/NaN, true for other values, 
        * including 0/false/''
        * @method isValue
        * @since 2.3.0
        * @param o {any} the item to test
        * @return {boolean} true if it is not null/undefined/NaN || false
        */
        isValue: function(o) {
            // return (o || o === false || o === 0 || o === ''); // Infinity fails
            return (L.isObject(o) || L.isString(o) || L.isNumber(o) || L.isBoolean(o));
        }

    };

    /**
    * Determines whether or not the property was added
    * to the object instance.  Returns false if the property is not present
    * in the object, or was inherited from the prototype.
    * This abstraction is provided to enable hasOwnProperty for Safari 1.3.x.
    * There is a discrepancy between YAHOO.lang.hasOwnProperty and
    * Object.prototype.hasOwnProperty when the property is a primitive added to
    * both the instance AND prototype with the same value:
    * <pre>
    * var A = function() {};
    * A.prototype.foo = 'foo';
    * var a = new A();
    * a.foo = 'foo';
    * alert(a.hasOwnProperty('foo')); // true
    * alert(YAHOO.lang.hasOwnProperty(a, 'foo')); // false when using fallback
    * </pre>
    * @method hasOwnProperty
    * @param {any} o The object being testing
    * @param prop {string} the name of the property to test
    * @return {boolean} the result
    */
    L.hasOwnProperty = (Object.prototype.hasOwnProperty) ?
    function(o, prop) {
        return o && o.hasOwnProperty(prop);
    } : function(o, prop) {
        return !L.isUndefined(o[prop]) &&
                o.constructor.prototype[prop] !== o[prop];
    };

    // new lang wins
    OB.augmentObject(L, OB, true);

    /*
    * An alias for <a href="YAHOO.lang.html">YAHOO.lang</a>
    * @class YAHOO.util.Lang
    */
    YAHOO.util.Lang = L;

    /**
    * Same as YAHOO.lang.augmentObject, except it only applies prototype 
    * properties.  This is an alias for augmentProto.
    * @see YAHOO.lang.augmentObject
    * @method augment
    * @static
    * @param {Function} r  the object to receive the augmentation
    * @param {Function} s  the object that supplies the properties to augment
    * @param {String*|boolean}  arguments zero or more properties methods to 
    *        augment the receiver with.  If none specified, everything
    *        in the supplier will be used unless it would
    *        overwrite an existing property in the receiver.  if true
    *        is specified as the third parameter, all properties will
    *        be applied and will overwrite an existing property in
    *        the receiver
    */
    L.augment = L.augmentProto;

    /**
    * An alias for <a href="YAHOO.lang.html#augment">YAHOO.lang.augment</a>
    * @for YAHOO
    * @method augment
    * @static
    * @param {Function} r  the object to receive the augmentation
    * @param {Function} s  the object that supplies the properties to augment
    * @param {String*}  arguments zero or more properties methods to 
    *        augment the receiver with.  If none specified, everything
    *        in the supplier will be used unless it would
    *        overwrite an existing property in the receiver
    */
    YAHOO.augment = L.augmentProto;

    /**
    * An alias for <a href="YAHOO.lang.html#extend">YAHOO.lang.extend</a>
    * @method extend
    * @static
    * @param {Function} subc   the object to modify
    * @param {Function} superc the object to inherit
    * @param {Object} overrides  additional properties/methods to add to the
    *        subclass prototype.  These will override the
    *        matching items obtained from the superclass if present.
    */
    YAHOO.extend = L.extend;

})();
YAHOO.register("yahoo", YAHOO, {version: "2.6.0", build: "1321"});
